package com.example.portlocalforward.service;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.portlocalforward.controller.model.PortLocalForwardBaseMessageRequest;
import com.example.portlocalforward.controller.model.PortLocalForwardRequest;
import com.example.portlocalforward.controller.model.PortLocalForwardResponse;
import com.example.portlocalforward.entity.PortLocalForward;
import com.example.portlocalforward.entity.SshTunnel;
import com.example.portlocalforward.repository.PortLocalForwardRepository;
import com.example.portlocalforward.repository.SshTunnelRepository;
import com.example.portlocalforward.sshmanage.SessionAndPortLocalForwardContainer;

import lombok.extern.slf4j.Slf4j;

/**
 * 端口本地转发服务类
 * 负责管理端口本地转发
 * 
 * @author Generated
 * @version 1.0.0
 */
@Slf4j
@Service
@Transactional
public class PortLocalForwardService {

    @Autowired
    private PortLocalForwardRepository portLocalForwardRepository;

    @Autowired
    private SshTunnelRepository sshTunnelRepository;

    // @Autowired
    // private PortLocalForwardManage portLocalForwardManage;
    @Autowired
    private SessionAndPortLocalForwardContainer sessionAndPortLocalForwardContainer;

    /**
     * 获取所有端口本地转发
     * 
     * @return 端口本地转发列表（包含实时状态）
     */
    @Transactional(readOnly = true)
    public List<PortLocalForwardResponse> getAllPortLocalForwards() {
        log.info("获取所有端口本地转发");
        List<PortLocalForwardResponse> responses = portLocalForwardRepository.findAllWithSshTunnelName();
        sessionAndPortLocalForwardContainer.setStatus(responses);
        return responses;
    }

    /**
     * 创建端口本地转发
     * 
     * @param request 创建请求
     * @return 创建的端口本地转发
     */
    @Transactional(rollbackFor = Exception.class)
    public void createPortLocalForward(PortLocalForwardRequest request) {
        log.info("创建端口本地转发: {}", request.getName());

        // 验证SSH隧道是否存在
        Optional<SshTunnel> sshTunnelOpt = sshTunnelRepository.findById(request.getSshTunnelId());
        if (!sshTunnelOpt.isPresent()) {
            throw new RuntimeException("SSH隧道不存在，ID: " + request.getSshTunnelId());
        }

        // 校验重复：sshTunnelId + remoteHost + remotePort + localPort 的组合不能重复
        Optional<PortLocalForward> duplicateOpt = portLocalForwardRepository
                .findBySshTunnelIdAndRemoteHostAndRemotePortAndLocalPort(
                        request.getSshTunnelId(),
                        request.getRemoteHost(),
                        request.getRemotePort(),
                        request.getLocalPort());
        if (duplicateOpt.isPresent()) {
            throw new RuntimeException(String.format(
                    "端口转发配置已存在，不能重复创建。转发名称: %s",
                    request.getName()));
        }

        PortLocalForward portLocalForward = new PortLocalForward();
        BeanUtils.copyProperties(request, portLocalForward);

        PortLocalForward saved = portLocalForwardRepository.save(portLocalForward);

        log.info("端口本地转发创建成功: {}", saved.getId());
    }

    /**
     * 更新端口本地转发
     * 
     * @param id      端口本地转发ID
     * @param request 更新请求
     * @return 更新后的端口本地转发
     */
    @Transactional(rollbackFor = Exception.class)
    public void updatePortLocalForward(Long id, PortLocalForwardRequest request) {
        log.info("更新端口本地转发: {}", id);

        Optional<PortLocalForward> optional = portLocalForwardRepository.findById(id);
        if (!optional.isPresent()) {
            throw new RuntimeException("端口本地转发不存在，ID: " + id);
        }

        // 验证SSH隧道是否存在
        Optional<SshTunnel> sshTunnelOpt = sshTunnelRepository.findById(request.getSshTunnelId());
        if (!sshTunnelOpt.isPresent()) {
            throw new RuntimeException("SSH隧道不存在，ID: " + request.getSshTunnelId());
        }

        // 校验重复：sshTunnelId + remoteHost + remotePort + localPort 的组合不能重复（排除自身）
        Optional<PortLocalForward> duplicateOpt = portLocalForwardRepository
                .findBySshTunnelIdAndRemoteHostAndRemotePortAndLocalPort(
                        request.getSshTunnelId(),
                        request.getRemoteHost(),
                        request.getRemotePort(),
                        request.getLocalPort());
        if (duplicateOpt.isPresent() && !duplicateOpt.get().getId().equals(id)) {
            throw new RuntimeException(String.format(
                    "端口转发配置已存在，不能重复。转发名称: %s",
                    request.getName()));
        }

        List<PortLocalForwardResponse> portLocalForwardResponses = portLocalForwardRepository
                .findAllWithSshTunnelNameByIds(Arrays.asList(id));
        if (CollectionUtils.isEmpty(portLocalForwardResponses)) {
            throw new RuntimeException("端口本地转发不存在，ID: " + id);
        }
        if (sessionAndPortLocalForwardContainer.isRunning(portLocalForwardResponses)) {
            throw new RuntimeException("端口本地转发正在运行，不能更新");
        }

        PortLocalForward existing = optional.get();

        // 更新字段
        existing.setName(request.getName());
        existing.setSshTunnelId(request.getSshTunnelId());
        existing.setLocalPort(request.getLocalPort());
        existing.setRemoteHost(request.getRemoteHost());
        existing.setRemotePort(request.getRemotePort());
        existing.setUrl(request.getUrl());
        existing.setTags(request.getTags());

        portLocalForwardRepository.save(existing);

        log.info("端口本地转发更新成功: {}", id);
    }

    /**
     * 删除端口本地转发
     * 
     * @param id 端口本地转发ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void deletePortLocalForward(Long id) {
        log.info("删除端口本地转发: {}", id);

        List<PortLocalForwardResponse> portLocalForwardResponses = portLocalForwardRepository
                .findAllWithSshTunnelNameByIds(Arrays.asList(id));
        if (CollectionUtils.isEmpty(portLocalForwardResponses)) {
            throw new RuntimeException("端口本地转发不存在，ID: " + id);
        }
        if (sessionAndPortLocalForwardContainer.isRunning(portLocalForwardResponses)) {
            throw new RuntimeException("端口本地转发正在运行，不能删除");
        }
        // 删除数据库记录
        portLocalForwardRepository.deleteById(id);
        log.info("端口本地转发删除成功: {}", id);
    }

    /**
     * 批量启动端口本地转发
     * 
     * @param ids 端口本地转发ID列表
     * @return 启动结果Map，key为ID，value为是否成功
     */
    public List<String[]> batchStartPortLocalForwards(List<Long> ids) {
        log.info("批量启动端口本地转发: {}", ids);
        // 需要启动的端口本地转发列表
        List<PortLocalForwardResponse> portLocalForwardResponses = portLocalForwardRepository.findAllWithSshTunnelName()
                .stream()
                .filter(response -> ids.contains(response.getId()))
                .collect(Collectors.toList());
        return sessionAndPortLocalForwardContainer.add(portLocalForwardResponses);
    }

    /**
     * 批量停止端口本地转发
     * 
     * @param ids 端口本地转发ID列表
     * @return 停止结果Map，key为ID，value为是否成功
     */
    public void batchStopPortLocalForwards(List<Long> ids) {
        log.info("批量停止端口本地转发: {}", ids);
        // 需要停止的端口本地转发列表
        List<PortLocalForwardResponse> portLocalForwardResponses = portLocalForwardRepository.findAllWithSshTunnelName()
                .stream()
                .filter(response -> ids.contains(response.getId()))
                .collect(Collectors.toList());
        sessionAndPortLocalForwardContainer.remove(portLocalForwardResponses);
    }

    /**
     * 批量切换SSH隧道
     * 
     * @param ids            端口本地转发ID列表
     * @param newSshTunnelId 新的SSH隧道ID
     * @return 切换结果Map，key为ID，value为是否成功
     */
    @Transactional(rollbackFor = Exception.class)
    public void batchSwitchSshTunnel(List<Long> ids, Long newSshTunnelId) {
        log.info("批量切换SSH隧道: {} -> {}", ids, newSshTunnelId);

        // 验证SSH隧道是否存在
        Optional<SshTunnel> tunnelOpt = sshTunnelRepository.findById(newSshTunnelId);
        if (!tunnelOpt.isPresent()) {
            throw new RuntimeException("SSH隧道不存在，ID: " + newSshTunnelId);
        }
        List<PortLocalForwardResponse> portLocalForwardResponses = portLocalForwardRepository
                .findAllWithSshTunnelNameByIds(ids);
        if (sessionAndPortLocalForwardContainer.isRunning(portLocalForwardResponses)) {
            throw new RuntimeException("端口本地转发正在运行，不能切换SSH隧道");
        }

        for (Long id : ids) {
            Optional<PortLocalForward> optional = portLocalForwardRepository.findById(id);
            if (!optional.isPresent()) {
                continue;
            }

            PortLocalForward portLocalForward = optional.get();

            // 检查是否已经使用该SSH隧道
            if (portLocalForward.getSshTunnelId().equals(newSshTunnelId)) {
                continue;
            }

            // 更新SSH隧道ID
            portLocalForward.setSshTunnelId(newSshTunnelId);
            portLocalForwardRepository.save(portLocalForward);

        }
    }

    /**
     * 更新端口本地转发基础信息
     * 
     * @param id                                 端口本地转发ID
     * @param portLocalForwardBaseMessageRequest 端口本地转发基础信息请求
     */
    @Transactional(rollbackFor = Exception.class)
    public void updatePortLocalForwardBaseMessage(Long id,
            PortLocalForwardBaseMessageRequest portLocalForwardBaseMessageRequest) {
        log.info("更新端口本地转发基础信息: {}", id);
        Optional<PortLocalForward> optional = portLocalForwardRepository.findById(id);
        if (!optional.isPresent()) {
            throw new RuntimeException("端口本地转发不存在，ID: " + id);
        }
        PortLocalForward portLocalForward = optional.get();
        BeanUtils.copyProperties(portLocalForwardBaseMessageRequest, portLocalForward);
        portLocalForwardRepository.save(portLocalForward);
        log.info("端口本地转发基础信息更新成功: {}", id);
    }

}
